package com.cm.creational.singleton;

import lombok.Data;

/**
 * 懒汉式单例的几种写法。
 * 懒汉和饿汉的区别在于，是否在类加载时就会初始化实例，
 * 比如在饿汉中，只要类加载就会执行静态变量或静态代码块；
 * 在懒汉中，只有调用getInstance()明确要获取单例对象时，才会进行实例化，如果调用test()则不会进行实例化
 * @author cm.g
 * @date 2023/6/9 14:31
 */
public class SingletonIdler {

    public static void test(){
        System.out.println("调用懒汉式单例的普通静态方法，此时单例："+singletonIdler);
    }
    private static volatile SingletonIdler singletonIdler;

    /**
     * 1.单例模式的懒汉式[线程不安全，不可用]
     * 问题：为什么不安全？
     * 答案：2个线程进入此方法，其中一个线程进入if条件后，执行instance=new Singleton()跳出时，
     * 另一个线程也会执行instance=new Singleton()
     */
    public static SingletonIdler getInstance() {
        // 这里线程是不安全的,可能得到两个不同的实例
        if (singletonIdler == null) {
            singletonIdler = new SingletonIdler();
        }
        return singletonIdler;
    }

    /**
     * 2.懒汉式线程安全的:[线程安全，效率低不推荐使用]
     * <p>
     * 缺点：效率太低了，每个线程在想获得类的实例时候，执行getInstance()方法都要进行同步。
     * 而其实这个方法只执行一次实例化代码就够了，
     * 后面的想获得该类实例，直接return就行了。方法进行同步效率太低要改进。
     */
    public static synchronized SingletonIdler getInstance2() {
        if (singletonIdler == null){
            singletonIdler = new SingletonIdler();
        }
        return singletonIdler;
    }

    /**
     * 3.单例模式懒汉式[线程不安全，不可用]
     * <p>
     * 虽然加了锁，但是有2个线程同时进入if语句，一个线程拿到锁之后，执行`singletonIdler = new SingletonIdler()`，另一个线程拿到锁，又执行一次singletonIdler = new SingletonIdler()，
     * 这样就又创建了一个实例，浪费了资源，效率太低了，而且线程不安全，不推荐使用。
     */
    public static SingletonIdler getInstance3(){
        if (singletonIdler == null){
            synchronized (SingletonIdler.class){
                singletonIdler = new SingletonIdler();
            }
        }
        return singletonIdler;
    }
    /**
     * 4.单例模式懒汉式双重校验锁[推荐用]
     * 懒汉式变种,属于懒汉式的最好写法,保证了:延迟加载和线程安全
     */
    public static SingletonIdler getInstance4(){
        if (singletonIdler == null){
            synchronized (SingletonIdler.class){
                if (singletonIdler == null){
                    singletonIdler = new SingletonIdler();
                }
            }
        }
        return singletonIdler;
    }
}
